﻿using System;
using Grishko.DataTier;
using Grishko.SerilizeTools;
using Ecopsy.Tools;
using OutdoorLib.Context;
using System.Linq;
using OutdoorLib.BaseEntity.WS;
using OutdoorLib.BaseEntity.Agency;
using OutdoorLib.BaseEntity.Constraction;


namespace OutdoorLib.BaseEntity.Contract
{

    public class ContractSurfaceItemList : EntityList
    {
        /// <summary>
        /// Если в коллекции есть строчка пересекающаяся с данным периодом - изменяется имеющаяся строка
        /// Если в указанный отрезок примыкает к каой либо строке - строки сливаются
        /// Если нет пересечений формируется новая запись
        /// 
        /// </summary>
        /// <param name="SideID"></param>
        /// <param name="dtStart"></param>
        /// <param name="dtFinish"></param>
        /// <returns></returns>
        public  void  SetContractSurfaceItem(String SideID, 
                                                DateTime dtStart, 
                                                DateTime dtFinish,
                                                string ContractID , 
                                                int Cost)
        {
            this.Reset();
            foreach (ContractSurfaceItem i in this)// Ещем к какому сущ. отрезку можно присоседиться
            {
                if (i.SideID == SideID)
                {
                    int CrossType = DateTimeTools.GetCrossPeriod(dtStart, dtFinish, i.DtStart, i.DtFinish);
                    switch (CrossType)
                    {
                        //case 0: // нет пересечений - новый отрезок                                                         

                        //    ContractSurfaceItem ni = new ContractSurfaceItem()-
                        //    {
                        //        SideID = SideID,
                        //        ContractID = ContractID,
                        //        DtStart = dtStart,
                        //        DtFinish = dtFinish
                        //    };
                        //    this.Add(ni);
                        //    return;

                        case 1:// Если X входит в Y 
                            i.DtFinish = dtFinish;
                            i.DtStart = dtStart;
                            return;

                        case 7:// Если Y входит в X 
                            i.DtFinish = dtFinish;
                            i.DtStart = dtStart;
                            return;
                            

                        case 2:// пересечени слева                            
                            i.DtStart = dtStart;
                            return;
                        case 4:// периоды идентичны
                            this.Remove(i.ID);
                            return;

                        case 6: //примыкание справа
                            i.DtStart = dtStart;
                            return;
                        case 3://примыкание слева 
                            i.DtFinish  = dtFinish;
                            return;

                        //x Примыкает слева                        
                        case 5:
                            i.DtFinish = dtFinish;
                            return ;

                       
                    }                    

                }                
            }

            this.Reset();
            foreach (ContractSurfaceItem i in this)// Ещем к какому сущ. отрезку можно присоседиться
            {
                if (i.SideID == SideID)
                {
                    int CrossType = DateTimeTools.GetCrossPeriod(dtStart, dtFinish, i.DtStart, i.DtFinish);
                    switch (CrossType)
                    {
                        case 0: // нет пересечений - новый отрезок                                                         

                            ContractSurfaceItem ni = new ContractSurfaceItem()
                            {
                                SideID = SideID,
                                ContractID = ContractID,
                                DtStart = dtStart,
                                DtFinish = dtFinish
                            };
                            this.Add(ni);
                            return;
                    }
                }

            }

            ///Нет отрезков к которым можно присос. - доб. новый
            ContractSurfaceItem o = new ContractSurfaceItem()
            {
                SideID = SideID,
                ContractID = ContractID,
                DtStart = dtStart,
                DtFinish = dtFinish
            };
            this.Add(o);

        }

        public EntityList GetSideIDList()
        {
            EntityList l = new EntityList();
            foreach (ContractSurfaceItem i in this)
            {
                l.Add(new EntitySingle() { ID = i.SideID });
            }
            return l;
        }

        [EntityNonSerialized]
        public int Summa
        {
            get
            {
                int res = 0;
                foreach (ContractSurfaceItem i in this)
                {
                    res = res + i.Summa;
                }
                return res;
            }
        }

        /// <summary>
        /// Начало контракта
        /// </summary>
        /// <returns></returns>
        public DateTime GetMinStartDate()
        {
            if (this.Count == 0)
                return AgencyLib_GlobalConstants.MinDate ;

            return this.ToArray<ContractSurfaceItem>().Min(w => w.DtStart);
        }

        /// <summary>
        /// Окончание контракта
        /// </summary>
        /// <returns></returns>
        public DateTime GetMaxEndDate()
        {
            if (this.Count == 0) 
                return AgencyLib_GlobalConstants.MaxDate;

            return this.ToArray<ContractSurfaceItem>().Max(w => w.DtFinish);
        }


        ///// <summary>
        ///// Действ. след. правила - SurfaceId-такого периода в коллекции нет - добавляем
        ///// SurfaceId - есть и существ. период пересекается слева с добавляемым - сливаем сущ с добавл 
        ///// SurfaceId - есть и существ. период пересекается справа - удаляем сущ - пишем новый
        ///// SurfaceId - есть и существ. период не пересекается - формируем новую запись для SurfaceId
        ///// SurfaceId - есть и периоды полностью совп. - удаляем 
        ///// </summary>
        ///// <param name="obj"></param>
        //public override void Add(object obj)
        //{

        //    ContractSurfaceItem x = (ContractSurfaceItem)obj;
        //    ContractSurfaceItem y = (ContractSurfaceItem)this[x.ID];
        //    if (null == this[x.ID]) //SurfaceId-такого периода в коллекции нет - добавляем
        //    {
        //        base.Add(x);
        //        return;

        //    }
        //    int i = DateTimeTools.GetCrossPeriod(x.DtStart, x.DtFinish, y.DtStart, y.DtFinish);

        //    // не пересекаются
        //    if (i == 0)
        //    {
        //        this.Remove(y.ID);
        //        base.Add(x);
        //    }


        //    // периоды идентичны
        //    if (i == 4)
        //        this.Remove(y.ID);

        //    //x Примыкает справа
        //    if (6 == i || 3 == i)
        //    {
        //        y.DtStart = x.DtStart;
        //    }

        //    //x Примыкает слева
        //    if (5 == i)
        //    {
        //        y.DtFinish = x.DtFinish;
        //    }


        //    // Если X входит в Y 
        //    if (1 == i)
        //    {
        //        this.Remove(y.ID);
        //        base.Add(x);
        //    }

        //    // Если X левеее
        //    if (2 == i)
        //    {
        //        y.DtStart = x.DtStart;
        //    }

        //}
        public override void Add(EntitySingle  obj)
        {
            base.Add(obj);

        }
        

    }

    /// <summary>
    /// Контракт содержит перечень диапазонов с указанием стороны  
    /// </summary>
    public class ContractSurfaceItem : EntitySingle  
    {
        
        private string _SideID = string.Empty;
        public string SideID { get { return _SideID; } set { _SideID = value; } }

        private string _ContractID = string.Empty;
        public string ContractID { get { return _ContractID; } set { _ContractID = value; } }

        //private int _Weight = Contract_BusinesRulesEngine.defWeight_Advice;
        ///// <summary>
        /////  Вес периода - определяет положение в очереди - чем меньше вес тем выше приоритет в очереди
        /////  если период относиться к контракту =0
        ///// </summary>
        //public int Weight { get { return _Weight; } set { _Weight = value; } }

        private DateTime _DtStart = AgencyLib_GlobalConstants.MinDate;
        public DateTime DtStart { get { return _DtStart; } set { _DtStart = value; } }


        private int _qPrioritetLevel = 0;
        /// <summary>
        ///  Приоритет в очереди - вияет на операцию ContractStatus.SetStatusWeight
        /// </summary>
        public int qPrioritetLevel 
        { 
            get { return _qPrioritetLevel; } 
            set {                    
                _qPrioritetLevel = value;                
                
            } 
        }

        private DateTime _DtFinish = AgencyLib_GlobalConstants.MaxDate;
        public DateTime DtFinish { get { return _DtFinish; } set { _DtFinish = value; } }

        /// <summary>
        /// Сумма на которой сошлись 
        /// </summary>
        public int ConractPrice { get; set; }

        public int Summa
        {
            get
            {
                return DateTimeTools.GetDayDiff(DtFinish, DtStart) * this.ConractPrice;
            }
            set { ;}
        }

        /// <summary>
        /// Номер поверхности к которой будет привязан период 
        /// Какой поверхностью - привязана сторона к контракту
        /// </summary>
        [EntityNonSerialized]
        public int SurfaceNumber { get; set; }

        


        public Side GetSide()
        {
            wsConstractions ws = (wsConstractions)AgencyLib_GlobalConstants.CurrentAgency.WS_FactoryList[WS_FactoryList.wsKey_Constraction];
            ConstractionEntity c = ws.GetConstractionFromSideId(SideID);
            return (Side)c.SideList[SideID];
        }

        
        
    }
}